package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSearchDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author xzh
 * @since 2024-03-14
 */
@Service
@AllArgsConstructor(onConstructor_ = {@Lazy})
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final UserClient userClient;
    private final IInteractionReplyService interactionReplyService;
    private final CourseClient courseClient;
    private final SearchClient searchClient;
    //查看 课程分类名称
    private final CategoryCache categoryCache;
    private final CatalogueClient catalogueClient;
    private final InteractionReplyMapper replyMapper;

    @Override
    @Transactional
    public void saveQuestion(QuestionFormDTO questionFormDTO) {
        // 获得用户id
        Long userId = UserContext.getUser();
        // 拷贝
        InteractionQuestion question = BeanUtils.copyBean(questionFormDTO, InteractionQuestion.class);
        // 添加没有的字段
        question.setUserId(userId);
        question.setCreateTime(LocalDateTime.now());
        // 添加到数据库
        save(question);
    }

    /**
     * 修改问题
     *
     * @param id
     * @param questionFormDTO
     */
    @Override
    public void updateQuestion(Long id, QuestionFormDTO questionFormDTO) {
        InteractionQuestion question = BeanUtils.copyBean(questionFormDTO, InteractionQuestion.class);
        question.setId(id);
        updateById(question);
    }

    /**
     * 分页根据条件查询我的问题
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query) {
        // 1.参数校验，课程id和小节id不能都为空
        Long courseId = query.getCourseId();
        Long sectionId = query.getSectionId();
        if (courseId == null && sectionId == null) {
            throw new BadRequestException("课程id和小节id不能都为空");
        }
        // 2.分页查询
        Page<InteractionQuestion> page = lambdaQuery()
                .select(InteractionQuestion.class, info -> !info.getProperty().equals("description"))
                .eq(query.getOnlyMine(), InteractionQuestion::getUserId, UserContext.getUser())
                .eq(courseId != null, InteractionQuestion::getCourseId, courseId)
                .eq(sectionId != null, InteractionQuestion::getSectionId, sectionId)
                .eq(InteractionQuestion::getHidden, false)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }
        // 3.根据id查询提问者和最近一次回答的信息
        Set<Long> userIds = new HashSet<>();
        Set<Long> answerIds = new HashSet<>();
        // 3.1.得到问题当中的提问者id和最近一次回答的id
        for (InteractionQuestion q : records) {
            if(!q.getAnonymity()) { // 只查询非匿名的问题
                userIds.add(q.getUserId());
            }
            answerIds.add(q.getLatestAnswerId());
        }
        // 3.2.根据id查询最近一次回答
        answerIds.remove(null);
        Map<Long, InteractionReply> replyMap = new HashMap<>(answerIds.size());
        if(CollUtils.isNotEmpty(answerIds)) {
            List<InteractionReply> replies = replyMapper.selectBatchIds(answerIds);
            for (InteractionReply reply : replies) {
                replyMap.put(reply.getId(), reply);
                if(!reply.getAnonymity()){ // 匿名用户不做查询
                    userIds.add(reply.getUserId());
                }
            }
        }

        // 3.3.根据id查询用户信息（提问者）
        userIds.remove(null);
        Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
        if(CollUtils.isNotEmpty(userIds)) {
            List<UserDTO> users = userClient.queryUserByIds(userIds);
            userMap = users.stream()
                    .collect(Collectors.toMap(UserDTO::getId, u -> u));
        }

        // 4.封装VO
        List<QuestionVO> voList = new ArrayList<>(records.size());
        for (InteractionQuestion r : records) {
            // 4.1.将PO转为VO
            QuestionVO vo = BeanUtils.copyBean(r, QuestionVO.class);
            vo.setUserId(null);
            voList.add(vo);
            // 4.2.封装提问者信息
            if(!r.getAnonymity()){
                UserDTO userDTO = userMap.get(r.getUserId());
                if (userDTO != null) {
                    vo.setUserId(userDTO.getId());
                    vo.setUserName(userDTO.getName());
                    vo.setUserIcon(userDTO.getIcon());
                }
            }

            // 4.3.封装最近一次回答的信息
            InteractionReply reply = replyMap.get(r.getLatestAnswerId());
            if (reply != null) {
                vo.setLatestReplyContent(reply.getContent());
                if(!reply.getAnonymity()){// 匿名用户直接忽略
                    UserDTO user = userMap.get(reply.getUserId());
                    vo.setLatestReplyUser(user.getName());
                }

            }
        }

        return PageDTO.of(page, voList);
    }

    /**
     * 根据问题id查询问题详情
     *
     * @param id
     * @return
     */
    @Override
    public QuestionVO queryQuestionById(Long id) {
        // 获得当前用户id
        Long userId = UserContext.getUser();
        // 根据问题id获得问题详情
        InteractionQuestion question = lambdaQuery().eq(InteractionQuestion::getId, id).one();

        if(question==null){
            throw new BadRequestException("问题不存在");
        }
        // 整理,封装对象
        QuestionVO vo = BeanUtils.copyBean(question, QuestionVO.class);
        // 判断用户是不是匿名提问
        if (question.getHidden()){
            return vo;
        }
        // 根据用户id获得用户昵称
        UserDTO userDTO = userClient.queryUserById(userId);
        vo.setUserName(userDTO.getName());
        vo.setUserIcon(userDTO.getIcon());
        return vo;
    }

    /**
     * 删除我的问题
     *
     * @param id
     */
    @Override
    @Transactional
    public void deleteMyQuestionById(Long id) {
        //1.判断问题是否存在
        InteractionQuestion question = lambdaQuery().eq(InteractionQuestion::getId, id).one();
        if (question == null) {
            log.debug("删除的问题不存在");
            throw new BadRequestException("删除的问题不存在");
        }
        //2.判断是不是我的问题
        Long userId = UserContext.getUser();
        if (!userId.equals(question.getUserId())) {
            //3.不是则抛出异常
            throw new BadRequestException("只能删除自己的问题");
        }
        //4.删除问题以及相关评论
        removeById(id);
        interactionReplyService.remove(new QueryWrapper<InteractionReply>()
                .lambda()
                .eq(InteractionReply::getQuestionId,id)
        );

    }

    /**
     * 管理端问题分页查询
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionAdminVO> queryAdminQuestionsPage(QuestionAdminPageQuery query) {
        //调用SearchClient工具类 进行模糊查询  返回含有关键字的课程id
        List<Long> courseIds = null;

        //课程名称不为空 则进行模糊查询
        if (StringUtils.isNotBlank(query.getCourseName())) {
            courseIds = searchClient.queryCoursesIdByName(query.getCourseName());
            //模糊查询结果为空则直接返回
            if (CollUtils.isEmpty(courseIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }


        //问题状态 有无查看, bengtime endtime
        Integer status = query.getStatus();
        LocalDateTime endTime = query.getEndTime();
        LocalDateTime beginTime = query.getBeginTime();
        Page<InteractionQuestion> page = lambdaQuery()
                .eq(status!= null, InteractionQuestion::getStatus, query.getStatus())
                .in(courseIds!=null,InteractionQuestion::getCourseId, courseIds)
                .le(endTime!= null, InteractionQuestion::getCreateTime, query.getEndTime())
                .ge(beginTime!= null, InteractionQuestion::getCreateTime, query.getBeginTime())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());

        //获得分页集合资源
        List<InteractionQuestion> records = page.getRecords();

        //健壮性判断
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        //提问者名称id集合
        Set<Long> userIds = new HashSet<>();
        //课程名称id集合
        Set<Long> cuids = new HashSet<>();
        //课程章节id集合
        Set<Long> cataIds = new HashSet<>();

        //遍历获得各种数据的id集合
        for (InteractionQuestion question : records) {
            userIds.add(question.getUserId());
            cuids.add(question.getCourseId());
            cataIds.add(question.getChapterId());
            cataIds.add(question.getSectionId());
        }

        //根据id查询用户
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userMap = new HashMap<>(userDTOS.size());
        if (CollUtils.isNotEmpty(userDTOS)) {
            userMap = userDTOS.stream()
                    .collect(Collectors.toMap(UserDTO::getId, u -> u));
        }

        //根据id查询课程
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(cuids);
        Map<Long, CourseSimpleInfoDTO> cInfoMap = new HashMap<>(simpleInfoList.size());
        if (CollUtils.isNotEmpty(simpleInfoList)) {
            cInfoMap = simpleInfoList.stream()
                    .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        }

        //根据id查询章节
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(cataIds);
        Map<Long, String> cataMap = new HashMap<>(cataSimpleInfoDTOS.size());
        if (CollUtils.isNotEmpty(cataSimpleInfoDTOS)) {
            cataMap = cataSimpleInfoDTOS.stream()
                    .collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
        }
        //循环遍历拷贝对象到vo
        List<QuestionAdminVO> listvo = new ArrayList<>(records.size());

        for (InteractionQuestion question : records) {
            //拷贝vo对象
            QuestionAdminVO vo = BeanUtils.copyBean(question, QuestionAdminVO.class);
            //放入提问者昵称
            UserDTO userDTO = userMap.get(question.getUserId());
            if (userDTO != null) {
                vo.setUserName(userDTO.getName());
            }
            //放入课程名称
            CourseSimpleInfoDTO cinf = cInfoMap.get(question.getCourseId());
            if (cinf != null) {
                vo.setCourseName(cinf.getName());
                //放入三级分类名称
                vo.setCategoryName(categoryCache.getCategoryNames(cinf.getCategoryIds()));
            }
            //放入章节名
            vo.setChapterName(cataMap.getOrDefault(question.getChapterId(), ""));
            vo.setSectionName(cataMap.getOrDefault(question.getSectionId(), ""));

            listvo.add(vo);
        }

        return PageDTO.of(page, listvo);
    }

    /**
     * 管理员修改问题是否可见
     *
     * @param id
     * @param hidden
     */
    @Override
    public void updateQuestionHiddenById(Long id, Boolean hidden) {
        boolean update = lambdaUpdate().eq(InteractionQuestion::getId, id)
                .set(InteractionQuestion::getHidden, hidden)
                .update();
        if (!update) {
            throw new DbException("问题状态修改失败");
        }
    }

    /**
     * 管理端通过问题id查看问题详情
     *
     * @param id
     * @return
     */
    @Override
    public QuestionAdminVO adminGetQuestionById(Long id) {
        // 1.拷贝
        InteractionQuestion question = lambdaQuery().eq(InteractionQuestion::getId, id).one();
        QuestionAdminVO vo = BeanUtils.copyBean(question, QuestionAdminVO.class);

        // 2.获得老师名称 课程名称
        CourseSearchDTO searchInfo = courseClient.getSearchInfo(question.getCourseId());
        vo.setCourseName(searchInfo.getName());
        UserDTO userDTO = userClient.queryUserById(searchInfo.getTeacher());
        vo.setTeacherName(userDTO.getName());

        // 3.获得三级分类名称
        CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(question.getSectionId(), false, false);
        String categoryNames = categoryCache.getCategoryNames(courseInfoById.getCategoryIds());
        vo.setCategoryName(categoryNames);


        // 4.获得章节名称
        List<Long> cataIds =new ArrayList<>(1);
        cataIds.add(question.getChapterId());
        String cataName = catalogueClient.batchQueryCatalogue(cataIds).get(0).getName();
        vo.setCategoryName(cataName);

        List<Long> sectIds =new ArrayList<>(1);
        sectIds.add(question.getSectionId());
        String sectName = catalogueClient.batchQueryCatalogue(sectIds).get(0).getName();
        vo.setSectionName(sectName);

        // 5.获得提问者名称
        String userName = userClient.queryUserById(question.getUserId()).getName();
        vo.setUserName(userName);

        // ****逻辑:如果问题被管理员查看了就应该改变问题状态为 已被查看 若状态为未被查看的情况下
        if (question.getStatus()==0){
            question.setStatus(1);

            //更改问题状态为已查看
            updateById(question);
        }

        // 6.返回
        return vo;
    }
}
